package org.dreamwork.cai.io.netty;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageDecoder;
import io.netty.handler.codec.MessageToByteEncoder;
import org.dreamwork.cai.internal.pojo.JsonInvocationPayload;
import org.dreamwork.cai.internal.pojo.JsonInvocationResult;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.nio.charset.StandardCharsets;
import java.util.List;

public class Codec {
    public static class Decoder extends ByteToMessageDecoder {
        private final Logger logger = LoggerFactory.getLogger (Decoder.class);

        private enum Status { HEADER, BODY }

        private Status status = Status.HEADER;
        private int length;

        @Override
        protected void decode (ChannelHandlerContext context, ByteBuf in, List<Object> out) throws Exception {
            switch (status) {
                case HEADER:
                    if (in.readableBytes () < 2) {
                        return;
                    }
                    length = in.readUnsignedShort ();
                    status = Status.BODY;

                case BODY:
                    if (in.readableBytes () < length) {
                        return;
                    }
                    byte[] buff = new byte[length];
                    in.readBytes (buff);
                    String content = new String (buff, StandardCharsets.UTF_8);
                    Gson g = new Gson ();
                    JsonInvocationPayload payload = g.fromJson (content, JsonInvocationPayload.class);
                    if (logger.isTraceEnabled ()) {
                        Gson p = new GsonBuilder ().setPrettyPrinting ().create ();
                        logger.trace ("received request:\r\n{}", p.toJson (payload));
                    }
                    out.add (payload);
                    status = Status.HEADER;
            }
        }
    }

    public static class Encoder extends MessageToByteEncoder<JsonInvocationResult> {
        @Override
        protected void encode (ChannelHandlerContext context, JsonInvocationResult result, ByteBuf out) {
            if (result != null) {
                Gson g = new Gson ();
                String content = g.toJson (result);
                byte[] buff = content.getBytes (StandardCharsets.UTF_8);

                int length = buff.length;
                out.writeShort (length).writeBytes (buff);
            }
        }
    }
}